package com.talkyun.openx.ocean.wrapper;

import com.talkyun.openx.ocean.base.HttpInterceptor;
import com.talkyun.openx.ocean.base.HttpRequest;
import com.talkyun.openx.server.AbstractHandler;
import com.talkyun.openx.server.core.InterceptorException;
import com.talkyun.utils.json.JSON;
import com.talkyun.utils.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.FilterChain;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Map;

public class HttpInterceptorHandler extends AbstractHandler {
    private static final Logger logger = LoggerFactory.getLogger(HttpInterceptorHandler.class);
    private static final String _OPENX_HEADER = "_openx_header";
    private List<HttpInterceptor> list;

    public HttpInterceptorHandler(ServletContext sc, List<HttpInterceptor> list) {
        this.list = list;
        String context = sc.getContextPath();
        logger.info("Create http handler: {} ", isBlank(context) ? "/" : context);
    }

    public void handle(HttpServletRequest req, HttpServletResponse resp, FilterChain fc) throws IOException, ServletException {
        // 1. servlet handle
        String session = req.getSession().getId();

        HttpRequest http = new HttpRequest(session);
        http.setUrl(req.getRequestURL().toString());
        http.setMethod(req.getMethod());
        this.readHeader(req, http);

        // 2. do interceptor
        this.doInvoke(http);

        // 3. return http
        fc.doFilter(req, resp);
    }

    private void doInvoke(HttpRequest http) {
        List<HttpInterceptor> list = this.getInterceptor();
        for (HttpInterceptor it : list) {
            try {
                it.doGetIn(http);
            } catch (InterceptorException ie) {
                throw ie;
            } catch (Throwable t) {
                throw new InterceptorException(it.getClass().getName(), t);
            }
        }
    }

    private void readHeader(HttpServletRequest req, HttpRequest http) {
        // TODO from http header

        // from cookie
        try {
            JSONObject cksJson = null;
            Cookie[] cookies = req.getCookies();
            for (int i = 0; cookies != null && i < cookies.length; i++) {
                Cookie cookie = cookies[i];
                if (_OPENX_HEADER.equalsIgnoreCase(cookie.getName())) {
                    String text = decodeFromB62(cookie.getValue());
                    cksJson = JSON.parseObject(text);
                    break;
                }
            }
            if (cksJson != null) {
                for (Map.Entry entry : cksJson.toMap().entrySet()) {
                    String key = entry.getKey().toString();
                    String val = entry.getValue().toString();
                    http.head(key, val);
                }
            }
        } catch (Throwable t) {
            logger.warn("Handle cookie header error!", t);
        }

        // from qs ('_openx_header')
        try {
            String header = req.getParameter(_OPENX_HEADER);
            if (isBlank(header)) {
                return;
            }

            header = decodeFromB62(header);
            JSONObject urlJson = JSON.parseObject(header);
            for (Map.Entry entry : urlJson.toMap().entrySet()) {
                String key = entry.getKey().toString();
                String val = entry.getValue().toString();
                http.head(key, val);
            }
        } catch (Throwable t) {
            logger.warn("Handle query string header error!", t);
        }
    }

    private List<HttpInterceptor> getInterceptor() {
        return list == null ? Collections.<HttpInterceptor>emptyList() : list;
    }

}